#include "component.h"
#include "device.h"
#include "xunmei.h"

#define logout(format, ...)             OSAL_LOG(C_LIGHT_PURPLE format C_NONE, ##__VA_ARGS__)
#define __logout(format, ...)           __OSAL_LOG(C_LIGHT_PURPLE format C_NONE, ##__VA_ARGS__)


static uint32_t xunmei_init_flag = 0;
__NVRAM static uint8_t xm_wake_flag = 0;

__EFRAM static uint16_t xm_ready = 150;

/* 定义虚拟硬件接口 */
#define XUNMEI_UART_VHWL                vUART_4
#define XUNMEI_WAKE_PIN_VHWL            vPIN_I3
#define XUNMEI_CTRL_PIN_VHWL            vPIN_C8

#define MAX_PACKAGE_LEN                 (512)           //最大包长
#define EVENT_XUNMEI_PROTOCOL           (0X00000001)    //协议处理事件
#define XUNMEI_PROTOCOL_PROC_CYCLE      10              //协议处理间隔时间

#define CMD_PACKET_STX                  0XF5    //命令包数据头
#define ACK_PACKET_STX                  0X5F    //应答包数据头

#define PROTOCOL_SEND_TIMES             3      //锁发送命令包的最大次数
#define PROTOCOL_RESEND_CMD_TIMEOUT     200    //锁重发命令包间隔时间ms
#define PROTOCOL_SEND_ACK_TIME_GAP      20     //锁发出多包ACK的间隔时间ms

#define PROTOCOL_WAKE_TIMES             3      //锁发送唤醒信号的最大次数
#define PROTOCOL_RESEND_WAKE_TIMEOUT    200    //锁重发唤醒信号的间隔时间ms
#define PROTOCOL_XM_SLEEP_TIME          300    //讯美模组的休眠时间（300ms未动作就休眠了）

#define UART_REV_DATA_BUF_LEN           (MAX_PACKAGE_LEN*2)    //串口接收缓冲区长度

#if defined(WFV01)
#define MULTI_JSON_RB_LEN               10
#else
#define MULTI_JSON_RB_LEN               2
#endif
#define GENERAL_JSON_RB_LEN             10
#define GENERAL_CMD_RB_LEN              10

#pragma pack(1)
/* 协议头结构 */
typedef struct
{
	uint8_t stx;  //数据头
	uint16_t crc16; //校验和
	uint16_t len;  //数据长度
    uint8_t cmd;
    uint8_t psn;
}ProtocolDataHead_stu_t;

/* 命令包结构 */
typedef struct
{
	ProtocolDataHead_stu_t head;
	uint8_t dataBuf[];//数据域长度不定
}CmdPacket_stu_t;

/* 应答包结构 */
typedef struct
{
	ProtocolDataHead_stu_t head;
	uint8_t ret;
    uint8_t databuf[];
}AckPacket_stu_t;
#pragma pack()

//多包JSON缓冲区结构
typedef struct 
{
	uint16_t  len;                           	//数据长度
    uart_send_cb_fun_t cb;                  	//发送命令回调（为NULL：不需要回调）
	uint8_t  buffer[MAX_PACKAGE_LEN];       	//发送缓存
}uart_txcmd_packet_stu_t;

//单包JSON缓冲区结构
typedef struct 
{
	uint16_t  len;                           	//数据长度
    uart_send_cb_fun_t cb;                  	//发送命令回调（为NULL：不需要回调）
	uint8_t  buffer[490+20];       				//发送缓存
}json_uart_txcmd_packet_stu_t;

//命令缓冲区结构
typedef struct 
{
	uint16_t  len;                           	//数据长度
    uart_send_cb_fun_t cb;                  	//发送命令回调（为NULL：不需要回调）
	uint8_t  buffer[80];       					//发送缓存
}cmd_uart_txcmd_packet_stu_t;

/* 命令包发送状态信息 */
__EFRAM static struct
{
    uart_txcmd_packet_stu_t data;     			//数据
    uint8_t tsn;
    uint8_t cmd;
	uint32_t timeStamp;               			//最后一次发送的时间戳
	uint8_t  cnt;                    			//命令发送次数（可能重发）
	uint8_t  wake_cnt;                    	    //唤醒信号发送次数（可能重发）
	enum
	{                                 			//当前发送的状态
		TX_STA_IDLE,                  			//空闲
		TX_STA_WAIT_ACK,              			//等待模块回复应答包
        TX_STA_WAIT_NOTIFY,                     //等待唤醒通知
	}status;
    RingBufferHandle_t Tx_rb_json_list_recode_handle;//记录和密码列表json包缓冲区
    RingBufferHandle_t Tx_rb_json_handle;//其他json包缓冲区
    RingBufferHandle_t Tx_rb_cmd_handle;//命令包缓冲区
}CmdPacketTxInfo;

/* 命令包接收状态信息 */
__EFRAM static struct
{
    RingBufferHandle_t Rx_rbHandle;
    uint8_t tsn;
    uint32_t timeStamp;               		//最后一次收到数据包的时间戳
    uint8_t uart_rev_data[MAX_PACKAGE_LEN];
}CmdPacketRxInfo;

/**
  * @brief  故障处理
  * @note
  * @param  err：是否故障
  * @return void
  */
static void err_process(uint8_t err)
{
    static uint8_t err_flag = 0xff;
    if (err != err_flag)
    {
        err_flag = err;
        OSAL_MessagePublishErrorCode(ERRCODE_TYPE_XUNMEI, err_flag);
    }
}

/**
  * @brief  计算CRC校验
  * @note
  *
  * @param  puchMsg：数据指针
  * @param  usDataLen：数据长度
  */
static uint16_t CRC16_XMODEM(uint8_t *puchMsg, uint32_t usDataLen)
{
    unsigned short wCRCin = 0x0000;
    unsigned short wCPoly = 0x1021;
    unsigned char wChar = 0;

    while (usDataLen--)
    {
        wChar = *(puchMsg++);
        wCRCin ^= (wChar << 8);

        for(int i = 0; i < 8; i++)
        {
            if(wCRCin & 0x8000)
            {
                wCRCin = (wCRCin << 1) ^ wCPoly;
            }
            else
            {
                wCRCin = wCRCin << 1;
            }
        }
    }
    return (wCRCin) ;
}

/**
  * @brief  打印HEX数据
  * @note
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  */
static void PrintfHexData(uint8_t *pData, uint16_t len,char *msg)
{
    char *str_buffer = OSAL_Malloc(len * 3 + 1);
    if (str_buffer != NULL)
    {
        memset(str_buffer,0,len * 3 + 1);
        __logout("[%ld]%s:%d(Bytes)\r\n",OSAL_GetTickCount(),msg,len);
        if (str_buffer != NULL)
        {
            for (int i=0; i<len; i++)
            {
                sprintf(&str_buffer[i*3], "%02X ", pData[i]);
            }
            __logout("%s\r\n\r\n", str_buffer);
        }
    }
	if (str_buffer) OSAL_Free(str_buffer);
}


/**
  * @brief  唤醒信号的定时器中断回调
  * @note   
  * @return 
  */
static void SendWakeSignal_Callback(TimerHandle_stu_t time)
{
    (void)time;

    /* 中断IO设置成数字高阻，讯美模块有上拉电阻 */
    logout("INT IO HIGH\r\n");
    Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, 1); 
    Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, PIN_MODE_INPUT_HIGHZ);
    InputPort_EnableProt("XUNMEI_WAKE");
}

/**
  * @brief  发出唤醒信号【10ms低脉冲】
  * @note   
  * @return 
  */
static int XunMei_SendWakeSignal(void)
{
    /* 中断IO设置成输出 */
    logout("INT IO LOW\r\n");
    InputPort_DisableProt("XUNMEI_WAKE");
    Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, PIN_MODE_OD_DRIVE);
    Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, 0);
    OSAL_TimerCreate(SendWakeSignal_Callback,10,RESET);
    return 0;
}

/**
  * @brief  加载待发送的数据
  * @note   将要发出的数据，填入发送缓存区
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @return 成功返回true，失败返回false
  */
static ErrorStatus XunMei_SendData(uint8_t *pData, uint16_t len)
{
    if (Device_Write(XUNMEI_UART_VHWL, pData, len, 0) != 0)
    {
        logout("Device_Write error\r\n");
        return ERROR;
    }
	PrintfHexData(pData, len, "SendData");
	return SUCCESS;
}

/**
  * @brief  处理超时重发
  *
  * @note   MCU发出命令包后，超时没有收到确认包，就重发
  */
static void XunMei_ProcessTimeoutResend(void)
{
    uint8_t send_timeout_msg = 0;
	uint32_t currentTime = OSAL_GetTickCount();

	if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK)//等待ACK包
	{
		if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp)  > PROTOCOL_RESEND_CMD_TIMEOUT)
		{
			logout(C_COLOR "wait cmd:0x%02X ACK timeout" C_NONE, CmdPacketTxInfo.cmd);
			if (CmdPacketTxInfo.cnt >= PROTOCOL_SEND_TIMES)//ERR:等待ACK包超时
			{
                logout("wait cmd:0x%02X ACK timeout than 3",CmdPacketTxInfo.cmd);
                send_timeout_msg = 1;
				CmdPacketTxInfo.status = TX_STA_IDLE;
                OSAL_SetTaskStatus(TASK_STA_NORMAL);
			}
			else
			{
                if (OSAL_PastTime(currentTime, CmdPacketRxInfo.timeStamp) < PROTOCOL_XM_SLEEP_TIME)//模组活跃
                {
                    XunMei_SendData(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);//直接重发数据包
                }
                else//不活跃
                {
					XunMei_SendWakeSignal();// 拉wake
                    CmdPacketTxInfo.status = TX_STA_WAIT_NOTIFY;
                    CmdPacketTxInfo.wake_cnt = 1;
                }
                CmdPacketTxInfo.timeStamp = currentTime;
                CmdPacketTxInfo.cnt++;
			}
		}
	}
    else if (CmdPacketTxInfo.status == TX_STA_WAIT_NOTIFY)
    {
        if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp)  > PROTOCOL_RESEND_WAKE_TIMEOUT)//等唤醒通知超时
        {
            logout("wait wake notify timeout, times:%d\r\n", CmdPacketTxInfo.wake_cnt);
            if (CmdPacketTxInfo.wake_cnt >= PROTOCOL_WAKE_TIMES)//ERR:等待唤醒通知超时
			{
                send_timeout_msg = 1;
				CmdPacketTxInfo.status = TX_STA_IDLE;
                OSAL_SetTaskStatus(TASK_STA_NORMAL);
                err_process(1);
			}
			else
            {
				XunMei_SendWakeSignal();//拉wake
                CmdPacketTxInfo.timeStamp = currentTime;
                CmdPacketTxInfo.wake_cnt++;
            }
        }
    }

    /* exec timeout callback */
    if(send_timeout_msg)
    {
        XunMeiMsg_t *tmp = (XunMeiMsg_t *)OSAL_Malloc(sizeof(XunMeiMsg_t));
        if(tmp)
        {
            tmp->msgType = XM_EXEC_CB;
            tmp->cb = CmdPacketTxInfo.data.cb;
            tmp->cmd = CmdPacketTxInfo.cmd;
            tmp->res = UART_SEND_WAIT_ACK_TIMEOUT;
            tmp->len = 0;
            OSAL_MessagePublish(tmp, sizeof(XunMeiMsg_t));
            OSAL_Free(tmp);
        }
        CmdPacketTxInfo.data.cb = NULL;
        CmdPacketTxInfo.cmd = 0;
    }
}

/**
  * @brief  处理接收的应答包
  * @note
  *
  * @param  pAckPacket：应答包数据指针
  */
static void ProcessRxAckPacket(AckPacket_stu_t *pAckPacket,uint16_t datalen)
{
	if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK)
	{
        logout("Receive ACK CMD:%02X,TSN:%d\r\n",pAckPacket->head.cmd,pAckPacket->head.psn);
		if (pAckPacket->head.psn == CmdPacketTxInfo.tsn && pAckPacket->head.cmd == CmdPacketTxInfo.cmd)
        {
            /* exec ack callback */
            XunMeiMsg_t *tmp = (XunMeiMsg_t *)OSAL_Malloc(sizeof(XunMeiMsg_t) + datalen);
            if(tmp)
            {
                tmp->msgType = XM_EXEC_CB;
                tmp->cb = CmdPacketTxInfo.data.cb;
                tmp->cmd = CmdPacketTxInfo.cmd;
                tmp->len = pAckPacket->head.len - 3;
                memcpy(tmp->data, pAckPacket->databuf, tmp->len);
                if (pAckPacket->ret == XUNMEI_EXE_OK)
                {
                    tmp->res = UART_SEND_SUCCEED;
                }
                else
                {
                    tmp->res = UART_SEND_ERROR;
                }
                OSAL_MessagePublish(tmp, sizeof(XunMeiMsg_t) + tmp->len);
                OSAL_Free(tmp);
            }
            CmdPacketTxInfo.data.cb = NULL; 
            CmdPacketTxInfo.status = TX_STA_IDLE;
            OSAL_SetTaskStatus(TASK_STA_NORMAL);
            CmdPacketTxInfo.cmd = 0;
        }
	}
}

/**
  * @brief  发出应答包
  * @note   MCU收到无线模组发过来命令后，通过调用该函数给模组回复应答包
  *
  * @param  cmd：命令
  * @param  res：命令处理结果
  * @param  pAckData：应答数据指针
  * @param  ackDataLen：数据长度
  */
static void SendAckPacket(uint8_t cmd,uint8_t res)
{
	uint8_t buffer[MAX_PACKAGE_LEN]={0};
	AckPacket_stu_t *pAckPacket = (AckPacket_stu_t *)buffer;

	pAckPacket->head.stx = ACK_PACKET_STX;
	pAckPacket->head.len = 3;
	pAckPacket->head.cmd = cmd;
    pAckPacket->head.psn = CmdPacketRxInfo.tsn;
	pAckPacket->ret = res;
	pAckPacket->head.crc16 = CRC16_XMODEM((uint8_t*)&(pAckPacket->head.cmd), pAckPacket->head.len);
    uint16_t send_len = sizeof(AckPacket_stu_t);
    if (Device_Write(XUNMEI_UART_VHWL,buffer,send_len,0) != 0)
    {
        logout("Device_Write error\r\n");
    }
	PrintfHexData(buffer, send_len,"TX ACK DATA");
}

/**
  * @brief  处理接收的命令包
  * @note
  *
  * @param  pCmdPacket：数据包指针
  */
static void ProcessRxCmdPacket(CmdPacket_stu_t *pCmdPacket,uint16_t datalen)
{
    logout("pCmdPacket->head.cmd :%02X\r\n",pCmdPacket->head.cmd);
    /* 收到了唤醒通知0x20 */
    if (pCmdPacket->head.cmd == TX_RX_CMD_WAKE_NOTIFI)
    {
        if (CmdPacketTxInfo.status == TX_STA_WAIT_NOTIFY)
        {
            logout("receive TX_STA_WAIT_NOTIFY  :%02X\r\n",((CmdPacket_stu_t*)CmdPacketTxInfo.data.buffer)->head.cmd);
            XunMei_SendData(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
            CmdPacketTxInfo.status = TX_STA_WAIT_ACK;//切换到等待ACK状态
			CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
        }
    }

    /* 数据转发到应用层 */
    XunMeiMsg_t *tmp = (XunMeiMsg_t *)OSAL_Malloc(sizeof(XunMeiMsg_t) + datalen);
    if (tmp != NULL)
    {
        tmp->msgType = XM_RECV_CMD_PACKET;
        tmp->cmd = pCmdPacket->head.cmd;
        tmp->len = pCmdPacket->head.len - 2;
        if (tmp->len > 0)
        {
            memcpy(tmp->data,pCmdPacket->dataBuf,tmp->len);
        }
        logout("OSAL_MessagePublish.....\r\n");
        if (OSAL_MessagePublish(tmp,sizeof(XunMeiMsg_t) + tmp->len) != SUCCESS)
        {
            logout("OSAL_MessagePublish error\r\n");   
        }
    }
    else
    {
        logout("OSAL_Malloc error\r\n");
    }
    CmdPacketRxInfo.tsn = pCmdPacket->head.psn;
    if (tmp) OSAL_Free(tmp);
}

/**
  * @brief  解析接收的数据包
  * @note
  *
  * @param  pData：数据包地址
  */
static void XunMei_ParseRxPacket(uint8_t *pData,uint16_t datalen)
{
	ProtocolDataHead_stu_t *pPacketHead = (ProtocolDataHead_stu_t *)pData;
    logout("pPacketHead->cmd == cmd:%02X\r\n",pPacketHead->cmd);
    if (pData == NULL)
    {
        return;
    }

    CmdPacketRxInfo.timeStamp = OSAL_GetTickCount();// 更新RX时间戳

	if (pPacketHead->stx == CMD_PACKET_STX)
	{
		/* 处理接收的命令包 */
        /* 丢弃重发包 */
        logout("xm pPacketHead->psn:%d\r\n",pPacketHead->psn);
        logout("xm CmdPacketRxInfo.tsn:%d\r\n",CmdPacketRxInfo.tsn);
        if (pPacketHead->psn == CmdPacketRxInfo.tsn && pPacketHead->psn != 0 && CmdPacketRxInfo.tsn != 0)
        {
            SendAckPacket(pPacketHead->cmd, 1);
            return;
        }
		ProcessRxCmdPacket((CmdPacket_stu_t *)pData,datalen);
	}
	else
	{
		/* 处理接收应答包 */
		ProcessRxAckPacket((AckPacket_stu_t *)pData,datalen);
	}
}

/**
  * @brief  从底层环形缓存获取一包数据并解析
  * @note   底层驱动收到数据，会暂存在环形缓存区
  * @param  out_data:解析后数据
  * @return 返回解析后的数据包长度，解析失败返回0
  */
static uint16_t XunMei_GetOnePacket(uint8_t *out_data)
{
	if (out_data == NULL) return 0;

	__EFRAM static uint8_t getPacketTimeoutCnt;
	uint16_t sum = 0, packetLen = 0;
	uint8_t tmpData; 
	uint32_t tmpLen = 0;
	uint8_t *protocolBuff;
    __EFRAM static uint16_t Cnt = 0;
	ProtocolDataHead_stu_t *pPacketHead;
 
    tmpLen = OSAL_RingBufferGetValidSize(CmdPacketRxInfo.Rx_rbHandle);
	if (tmpLen == 0)
	{
		if (++getPacketTimeoutCnt >= 3)
		{
			getPacketTimeoutCnt = 0;
			Cnt = 0;
		}
		return 0;
	}

	getPacketTimeoutCnt = 0;
	protocolBuff = out_data;
	for (; tmpLen; tmpLen--)
	{
        OSAL_RingBufferRead(CmdPacketRxInfo.Rx_rbHandle, &tmpData);
		// printf("%02X\r\n",tmpData);
		if (Cnt == 0)
		{
			if (tmpData == CMD_PACKET_STX || tmpData == ACK_PACKET_STX)         
			{
				protocolBuff[0] = tmpData;
				Cnt = 1;
			}
		}
		else if (Cnt > 0)     
		{
			protocolBuff[Cnt] = tmpData;
			Cnt = Cnt + 1;
			if (Cnt > 5)
			{
				pPacketHead = (ProtocolDataHead_stu_t *)protocolBuff;
				packetLen = pPacketHead->len + 5;
				if (Cnt >= MAX_PACKAGE_LEN || packetLen == Cnt)
				{
					if (packetLen == Cnt)
					{
						sum = CRC16_XMODEM(protocolBuff + 5, pPacketHead->len);
						if(pPacketHead->crc16 == sum)
						{
							if (pPacketHead->cmd != 0x11)//不是下发的JSON包数据
                            {
                                PrintfHexData(protocolBuff,Cnt,"REV DATA");
                            }
                            else
                            {
                                PrintfHexData(protocolBuff,sizeof(ProtocolDataHead_stu_t),"REV JSON-PACK");
                            }
							uint16_t data_len = Cnt;
							Cnt = 0;
							return data_len;
						}
						else
						{
							PrintfHexData(protocolBuff,Cnt,"CRC ERR");
						}
					}
					Cnt = 0;
					return 0;
				}
			}
		}
	}
	return 0;
}

/**
  * @brief  串口接收回调函数
  * @note        
  * @param  data:收到的数据
  * @param  len:数据长度
  * @return 
  */
static void XunMei_ReceiveCb(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    if (CmdPacketRxInfo.Rx_rbHandle == NULL)
    {
        return;
    }
    for (uint32_t i = 0; i < len; i++)
    {
        uint8_t tmp = ((uint8_t *)data)[i];
        if (OSAL_RingBufferWrite(CmdPacketRxInfo.Rx_rbHandle,&tmp) != SUCCESS)
        {
            return;
        } 
    }
}

/**
  * @brief  唤醒脚中断回调函数
  * @note        
  * @param  name：中断脚名字
  * @param  status:状态
  * @param  times:
  * @return 
  */
static void XunMei_WakeStatusChange(char *name, uint8_t status, uint8_t times)
{
    if (status == USER_ACTION_PRESS)
    {
        OSAL_EventCreateFromISR(COMP_XUNMEI);
    }
}

/**
  * @brief  协议层初始化
  *
  * @note   创建缓存、注册中断
  */
static void XunMei_ProtocolInit(void)
{
    if (xunmei_init_flag == 0)
    {
        xunmei_init_flag = UINT32_FLAG;
        CmdPacketTxInfo.status = TX_STA_IDLE;
        CmdPacketTxInfo.tsn = 0;
        CmdPacketRxInfo.Rx_rbHandle = OSAL_RingBufferCreate(UART_REV_DATA_BUF_LEN,1);
        CmdPacketTxInfo.Tx_rb_json_list_recode_handle = OSAL_RingBufferCreate(MULTI_JSON_RB_LEN, sizeof(uart_txcmd_packet_stu_t));
        CmdPacketTxInfo.Tx_rb_json_handle = OSAL_RingBufferCreate(GENERAL_JSON_RB_LEN,sizeof(json_uart_txcmd_packet_stu_t));	
        CmdPacketTxInfo.Tx_rb_cmd_handle = OSAL_RingBufferCreate(GENERAL_CMD_RB_LEN,sizeof(cmd_uart_txcmd_packet_stu_t));	

        Device_RegisteredCB(XUNMEI_UART_VHWL, XunMei_ReceiveCb);

        InputPort_stu_t button_list[] = {
        {"XUNMEI_WAKE", XUNMEI_WAKE_PIN_VHWL, INPUT_PORT_LOGIC_LOW, INPUT_PORT_FUNC_SINGLE}, //中断脚
        };

        /* 注册端口 */
        InputPort_Registered(button_list, OSAL_LENGTH(button_list), XunMei_WakeStatusChange);
        InputPort_EnableProt("XUNMEI_WAKE");
    }
}

/**
  * @brief  处理发送队列中的数据
  * @note        
  * @return 
  */
static void XunMei_ProcessTxQueue(void)
{
    uart_txcmd_packet_stu_t txcmd_packet = {0};

    if (xm_ready > 0)
    {
        xm_ready--;//讯美模组刚上电，还未就绪
        return;
    }

    if (CmdPacketTxInfo.status != TX_STA_IDLE)
    {
        return;
    }

    //同时多包JSON缓冲区没有数据和发送状态为空闲，避免发送多包JSON时插入其他指令,优先处理多包JSON缓冲区
    if (OSAL_RingBufferGetValidSize(CmdPacketTxInfo.Tx_rb_json_list_recode_handle) == 0)
	{
		if (OSAL_RingBufferRead(CmdPacketTxInfo.Tx_rb_cmd_handle, &txcmd_packet) == SUCCESS)//命令
		{
            logout("\r\n\r\nringbuffer read cmd:%02X\r\n",((CmdPacket_stu_t*)txcmd_packet.buffer)->head.cmd);
            goto exit;
		}
		else if (OSAL_RingBufferRead(CmdPacketTxInfo.Tx_rb_json_handle, &txcmd_packet) == SUCCESS)//普通JSON
		{
            logout("\r\n\r\ningbuffer read normal json cmd:%02X\r\n",((CmdPacket_stu_t*)txcmd_packet.buffer)->head.cmd);
			goto exit;	
		}
        return;	
	}

    if (OSAL_RingBufferRead(CmdPacketTxInfo.Tx_rb_json_list_recode_handle, &txcmd_packet) != SUCCESS)//记录和秘钥JSON,多包JSON
    {
        return;	
    }
    else
    {
        logout("\r\n\r\ningbuffer read record or keylist json cmd:%02X\r\n",((CmdPacket_stu_t*)txcmd_packet.buffer)->head.cmd);
    }
exit:
    CmdPacketTxInfo.data = txcmd_packet;
	CmdPacketTxInfo.cmd = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->head.cmd;
	CmdPacketTxInfo.tsn = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->head.psn;
    CmdPacketTxInfo.cnt = 1;
    CmdPacketTxInfo.wake_cnt = 1;
    uint32_t currentTime = OSAL_GetTickCount();
    if (OSAL_PastTime(currentTime, CmdPacketRxInfo.timeStamp)  < PROTOCOL_XM_SLEEP_TIME )//模组活跃
    {
        XunMei_SendData(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
        CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
        CmdPacketTxInfo.status = TX_STA_WAIT_ACK; //等待模块回复应答包
    }
    else
    {
		XunMei_SendWakeSignal();//拉wake
        CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();//刷新时间戳
        CmdPacketTxInfo.status = TX_STA_WAIT_NOTIFY; //等待唤醒通知
    }
    OSAL_SetTaskStatus(TASK_STA_ACTIVE);
}

/**
  * @brief  Uart任务 通信协议处理
  * @note   该函数会每间隔10ms执行一次
  */
static void XunMei_ProtocolPro(void)
{
	uint16_t len = XunMei_GetOnePacket(CmdPacketRxInfo.uart_rev_data);
	if (len > 0)
    {
        err_process(0);
        XunMei_ParseRxPacket(CmdPacketRxInfo.uart_rev_data,len);//解析数据
    }	
	XunMei_ProcessTimeoutResend(); //处理超时重发
    XunMei_ProcessTxQueue();
}

/**
  * @brief  立即发送
  * @note        
  * @param  data:需要发送的数据包
  * @return 0：成功，其他失败
  */
static int XunmeiSend_Now(uart_txcmd_packet_stu_t *data)
{
	if (data == NULL)
	{
		return -1;
	}

	memcpy(&CmdPacketTxInfo.data,data,sizeof(uart_txcmd_packet_stu_t));
	CmdPacketTxInfo.cmd = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->head.cmd;
	CmdPacketTxInfo.tsn = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->head.psn;
    CmdPacketTxInfo.cnt = 1;
    CmdPacketTxInfo.wake_cnt = 1;

    uint32_t currentTime = OSAL_GetTickCount();
    if (OSAL_PastTime(currentTime, CmdPacketRxInfo.timeStamp) < PROTOCOL_XM_SLEEP_TIME && CmdPacketRxInfo.timeStamp != 0)//模组活跃
    {
        XunMei_SendData(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
        CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
        CmdPacketTxInfo.status = TX_STA_WAIT_ACK; //等待模块回复应答包
    }
    else
    {
		XunMei_SendWakeSignal();//拉wake
        CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();//刷新时间戳
        CmdPacketTxInfo.status = TX_STA_WAIT_NOTIFY; //等待唤醒通知
        // if(CmdPacketRxInfo.timeStamp == 0)
        // {
        //     logout("CmdPacketRxInfo.timeStamp = 0  cmd:%02X\r\n",((CmdPacket_stu_t*)data->buffer)->head.cmd);
        //     if (OSAL_RingBufferWrite(CmdPacketTxInfo.Tx_rb_cmd_handle,data) != SUCCESS)
        //     {
        //         logout("OSAL_RingBufferWrite error\r\n");
        //         return -2;
        //     }
        // }
    }
	return 0;
}

/**
  * @brief  发出数据
  * @note        
  * @param  cmd:需要发送的命令
  * @param  pdata：命令数据
  * @param  len:数据长度
  * @param  cb:发送回调
  * @param  pack_type：包类型
  * @return 0：成功，其他失败
  */
static int XunmeiSend_Cmd(uint8_t cmd, uint8_t *pdata, uint16_t len, uart_send_cb_fun_t cb,cmd_packet_type pack_type)
{
    if (Device_Read(XUNMEI_CTRL_PIN_VHWL,NULL,0,0) == 1)
    {
        logout("Cancel cmd(0x%02X) sending, xm power is off\r\n", cmd);
        return -3;
    }

    if (pack_type == COMMAND_ACK)//发送ACK
    {
        if (pdata != NULL)
        {
            SendAckPacket(cmd,*pdata);
        }
        return 0;
    }

	uart_txcmd_packet_stu_t txcmd_packet = {0};
    __EFRAM static uint8_t tsn = 0;
    CmdPacket_stu_t *p_buffer = (CmdPacket_stu_t *)txcmd_packet.buffer;
    p_buffer->head.stx = CMD_PACKET_STX;
    p_buffer->head.len = len + 2;//有效数据域长度+cmd
    p_buffer->head.cmd = cmd;
    p_buffer->head.psn = tsn;
	if (pdata != NULL && len > 0)
    	memcpy(p_buffer->dataBuf, pdata, len);
    p_buffer->head.crc16 = CRC16_XMODEM(&(p_buffer->head.cmd), len + 2);
    txcmd_packet.len = sizeof(CmdPacket_stu_t) + len;//整个包数据长度
    txcmd_packet.cb = cb;
	tsn++;

	if (cmd == TX_RX_CMD_WAKE_NOTIFI)
	{
		XunMei_SendData((uint8_t*)p_buffer, sizeof(CmdPacket_stu_t) + len);
		// CmdPacketTxInfo.status = TX_STA_IDLE;
		return 0;
	}

    if (pack_type == JSON_PACKET_RECODE_LIST)
	{
		if (CmdPacketTxInfo.Tx_rb_json_list_recode_handle == NULL) return -1;
		if (OSAL_RingBufferWrite(CmdPacketTxInfo.Tx_rb_json_list_recode_handle, &txcmd_packet) != SUCCESS)
		{
			return -2;
		}
	}
	else if (pack_type == JSON_PACKET_NOMARL)
	{
		//同时多包JSON缓冲区没有数据和发送状态为空闲，避免发送多包JSON时插入其他指令
        if (OSAL_RingBufferGetValidSize(CmdPacketTxInfo.Tx_rb_json_list_recode_handle) == 0 && CmdPacketTxInfo.status == TX_STA_IDLE && xm_ready == 0)
		{
			return XunmeiSend_Now(&txcmd_packet);
		}
		else
		{
			if (CmdPacketTxInfo.Tx_rb_json_handle == NULL) return -1;
			if (OSAL_RingBufferWrite(CmdPacketTxInfo.Tx_rb_json_handle, &txcmd_packet) != SUCCESS)
			{
				logout("OSAL_RingBufferWrite error\r\n");
				return -2;
			}
		}
	}
	else if (pack_type == COMMAND)
	{
        //同时多包JSON缓冲区没有数据和发送状态为空闲，避免发送多包JSON时插入其他指令
        if (OSAL_RingBufferGetValidSize(CmdPacketTxInfo.Tx_rb_json_list_recode_handle) == 0 && CmdPacketTxInfo.status == TX_STA_IDLE && xm_ready == 0)
		{
			return XunmeiSend_Now(&txcmd_packet);
		}
		else
		{
			if (CmdPacketTxInfo.Tx_rb_cmd_handle == NULL) return -1;
            logout("OSAL_RingBufferWrite :%02X\r\n",((CmdPacket_stu_t*)txcmd_packet.buffer)->head.cmd);
			if (OSAL_RingBufferWrite(CmdPacketTxInfo.Tx_rb_cmd_handle, &txcmd_packet) != SUCCESS)
			{
				logout("OSAL_RingBufferWrite error\r\n");
				return -2;
			}
		}
	}
	
    return 0;
}

/**
  * @brief  判断协议层是否为空闲状态
  * @note
  *
  * @return 空闲：返回SUCCESS， 正忙：返回ERROR
  */
static ErrorStatus XunMei_IsProtocolIdle(void)
{
	/* 当前没有发出命令、发送缓存为空、接收的命令也处理完成了，才能发出新命令 */
	if ( CmdPacketTxInfo.status == TX_STA_IDLE)
	{
		return SUCCESS;
	}
	return ERROR;
}

/**
  * @brief  打开关闭讯美模块电源
  * @note
  * @param  onoff:SET，开 ; RESET，关
  * @return 
  */
static int XunMei_Power(FlagStatus onoff)
{
    logout("XunMei_Power Set:%d\r\n", onoff); 
    if (onoff == SET)
    {
        if (Device_Read(XUNMEI_CTRL_PIN_VHWL,NULL,0,0) == 1)
        {
            /* 讯美从断电到上电：改成1s后再与之交互 */
            logout("XunMei_Power: OFF --> ON\r\n");
            xm_ready = 150; //标记讯美需要150*10ms后，才允许发出数据
        }

        Device_Enable(XUNMEI_WAKE_PIN_VHWL); 
        Device_Enable(XUNMEI_UART_VHWL); 
        Device_Write(XUNMEI_CTRL_PIN_VHWL,NULL,0,0);

        /* 中断IO设置成数字高阻，开启中断 */
        Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, PIN_MODE_INPUT_HIGHZ);
        InputPort_EnableProt("XUNMEI_WAKE");
    }
    else
    {
        Device_Disable(XUNMEI_WAKE_PIN_VHWL);
        Device_Disable(XUNMEI_UART_VHWL);
        Device_Write(XUNMEI_CTRL_PIN_VHWL,NULL,0, 1);

        /* 中断IO设置成下拉低，禁用中断 */
        InputPort_DisableProt("XUNMEI_WAKE");
        Device_Write(XUNMEI_WAKE_PIN_VHWL,NULL,0, PIN_MODE_INPUT_PULLDOWN);
    }
	return 0;
}

/**
  * @brief  讯美模块任务函数
  * @note        
  * @param  event：当前任务的所有事件
  * @return 返回未处理的事件
  */
static uint32_t XunMei_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)        
    {
        logout("XunMei_Task Start\r\n"); 
        XunMei_ProtocolInit();  
        OSAL_EventRepeatCreate(COMP_XUNMEI, EVENT_XUNMEI_PROTOCOL, XUNMEI_PROTOCOL_PROC_CYCLE, EVT_PRIORITY_MEDIUM);
        SYS_API(XunmeiSend_Cmd);
        SYS_API(XunMei_SendWakeSignal);
        SYS_API(XunMei_IsProtocolIdle);
        SYS_API(XunMei_Power);

        if (xm_wake_flag != 0)
        {
            xm_wake_flag = 0;
            OSAL_EventCreateFromISR(COMP_XUNMEI);
        }
        return ( event ^ EVENT_SYS_START );  
    }

	if (event & EVENT_SYS_SLEEP)
	{
        Device_Disable(XUNMEI_UART_VHWL);  
        OSAL_EventDelete(COMP_XUNMEI, EVENT_XUNMEI_PROTOCOL); 
        return ( event ^ EVENT_SYS_SLEEP );
	}

	if (event & EVENT_XUNMEI_PROTOCOL)
	{
		XunMei_ProtocolPro();
		return ( event ^ EVENT_XUNMEI_PROTOCOL );
	}

	if (event & EVENT_SYS_ISR)
	{
		logout(C_CYAN"XUNMEI ISR\r\n"C_NONE);
        CmdPacketRxInfo.timeStamp = OSAL_GetTickCount();//更新RX时间戳
		XunmeiSend_Cmd(TX_RX_CMD_WAKE_NOTIFI,NULL,0,NULL,COMMAND);//唤醒通知
		return ( event ^ EVENT_SYS_ISR );
	}
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_XUNMEI, XunMei_Task, 0);

/**
  * @brief  唤醒逻辑处理
  *         当vPIN触发中断时，OS会调用该函数确认是否可以唤醒系统
  */
static int32_t XunMei_WakeupHandle(uint32_t dev)
{
    /* RAM数据未丢失，inputport会唤醒系统，这里wakehandle不用做任何处理 */
    if (xunmei_init_flag == UINT32_FLAG)
    {
        return -1;
    }

    /* RAM数据丢失了，PIN设备唤醒，要做消抖判断 */
    xm_wake_flag = 1;
    return 1;//TODO
}
COMPONENT_WAKEUP_EXPORT(COMP_XUNMEI, XunMei_WakeupHandle, XUNMEI_WAKE_PIN_VHWL);
